#!/usr/bin/python3
# coding=utf-8

import getopt
import sys
import time
import json
import re
import os
import requests
import pandas as pd
from urllib.parse import urlparse

FILE_TEMPLATE = """
#!/usr/bin/python3
#coding=utf-8

import json
import sys
sys.path.append("./")
sys.path.append("../")
sys.dont_write_bytecode = True
from utils.requests_helper import RequestsHelper
from utils.config_helper import PMS_Vars
from utils.logger_helper import Logger
from utils.jsonparse_helper import extract_content_from_response
from modules.pms_player import PMS_Player

ReqObj = RequestsHelper()


class {0}:
	
    def __init__(self, env, operator):
        self.env = env
        self.domain = PMS_Vars.get(env)['ENTRY']
        self.__get_access__(operator)
    
    def __get_access__(self, operator):
        if operator.is_logged:
            self.header = operator.req_header           
{1}

if __name__ == '__main__':
    env = 'FAT'
    user_name = YAML_Vars.get(env)['USER']
    user_pwd = YAML_Vars.get(env)['PWD']
    operator = Xforce_Player(env, user_name, user_pwd)
    operator.login()
    if operator.is_logged:
        demo = {0}(env, operator)
        tenantId = 1
        appInfo = demo.get_strategies(tenantId)
        print(appInfo)
"""

API_TEMPLATE_WITH_PATH_PARAM = """
    def {0}_{1}(self, {2}, **kwargs):
        url = self.domain + f'{3}'
        supported_params = {4}
        req_body = {5}
        res = ReqObj.{0}_req(url, params=None, data=None, headers=self.header)
        return extract_content_from_response(res)
"""

API_TEMPLATE_WITHOUT_PATH_PARAM = """
    def {0}_{1}(self, **kwargs):
        url = self.domain + '{2}'
        supported_params = {3}
        req_body = {4}
        res = ReqObj.{0}_req(url, params=None, data=None, headers = self.header)
        return extract_content_from_response(res)
"""


class AutoGenTestScripts:
    def __init__(self, swagger_url):
        self.domain = "http://www.xforceplus.com/api"
        self.req = requests.Session()
        self.swagger_info = self.req.get(swagger_url)
        self.swagger_json = json.loads(self.swagger_info.text)
        self.swagger_tags = self.swagger_json["tags"]
        self.swagger_definitions = self.swagger_json["definitions"]
        self.swagger_paths = self.swagger_json["paths"]

    def __extract_swagger_api_tags(self):
        # Step 2: 获取Swagger的Tags信息并简单转换成dict
        target_tags_mapping = {}
        for tag in self.swagger_tags:
            key = tag["name"]
            val = tag["description"].replace(
                " ", "_"
            )  # Swagger-UI 将tag中的空格用"_"代替，为后续用作文件名做准备
            target_tags_mapping[key] = val

        return target_tags_mapping

    def __extract_swagger_api_definitions_by_originRef(self, originRef):
        # Step 4: 基于Swagger Path中指定的originRef 字段匹配接口需要的请求体内容
        target_req_body = {}
        if self.swagger_definitions:
            for api_ref, req_definition in self.swagger_definitions.items():
                if api_ref == originRef:
                    properties = req_definition["properties"].keys()
                    target_req_body = dict(zip(list(properties), list(properties)))
                    break

        return target_req_body

    def __extract_swagger_api_paths_by_tag(self, api_method_info):
        # Step 3: 获取基于指定tag的Swagger的path的接口明细并组装API的定义
        req_body = None
        path_param = []
        query_param = []
        if api_method_info:
            for api_method, api_method_body in api_method_info.items():
                # 实际只有一轮循环
                # print(api_method)
                parameters = (
                    api_method_body["parameters"]
                    if "parameters" in api_method_body.keys()
                    else None
                )
                summary = api_method_body["summary"]
                tag = api_method_body["tags"][0]
                # 解析parameters
                if parameters:
                    for param in parameters:
                        try:
                            # 不确定是否只有一个param， 暂时就先按照parameters只有一条记录处理
                            if param["in"] == "body":
                                # 获取API对应的R ReqBody的入参
                                originRef = (
                                    param["schema"]["originalRef"]
                                    if "originalRef" in param["schema"].keys()
                                    else None
                                )
                                req_body = (
                                    self.__extract_swagger_api_definitions_by_originRef(
                                        originRef
                                    )
                                    if originRef
                                    else None
                                )

                            elif param["in"] == "path":
                                path_param.append(param["name"])

                            elif param["in"] == "query":
                                query_param.append(param["name"])

                            elif param["in"] == "formData":
                                # 判断是否可忽略
                                if not param["required"]:
                                    pass
                                else:
                                    print(
                                        f"API:{tag}-{summary}, 关键字段值= {param['in']} 自动解析失败，请手工补充。"
                                    )

                            else:
                                print(
                                    f"API:{tag}-{summary}, 关键字段值= {param['in']} 自动解析失败，请手工补充。"
                                )
                        except Exception as e:
                            print(summary, "\n", param)

                break

        return path_param, query_param, req_body

    def __generate_api_string(
        self, req_url, req_path, req_method, req_query_param, req_body
    ):
        # Step 5: 拼装API 方法
        api_def = ""
        api = re.sub(r"[{}]", "", req_url)  # 将特殊字符转换成空格
        api_names = api.split("/v1/")[-1]
        api_name = re.sub(r"[/-]", "_", api_names)  # 将特殊字符转换成下划线
        if req_path:
            api_def = API_TEMPLATE_WITH_PATH_PARAM.format(
                req_method, api_name, req_path, req_url, req_query_param, req_body
            )
        else:
            api_def = API_TEMPLATE_WITHOUT_PATH_PARAM.format(
                req_method, api_name, req_url, req_query_param, req_body
            )
        return api_def

    def __extract_swagger_api_paths(self, tag_name):
        # Step 1： 基于APIDoc的Tag进行API文件的拆分
        str_api_methods_by_tag = ""
        if self.swagger_paths:
            for req_url, api_method_info in self.swagger_paths.items():
                # req_url: 请求的方法
                # api_method_info: API请求内容，包含parameters，tags, consumes
                if req_url:
                    for k, v in api_method_info.items():
                        req_method = k  # 默认api_method = api_info.keys()[0]
                        api_method_tag = v["tags"][0]
                        if api_method_tag == tag_name:
                            (
                                req_path_params,
                                req_query_params,
                                req_body,
                            ) = self.__extract_swagger_api_paths_by_tag(api_method_info)
                            str_req_path_param = (
                                ", ".join(req_path_params) if req_path_params else None
                            )
                            api_method_definition_string = self.__generate_api_string(
                                req_url,
                                str_req_path_param,
                                req_method,
                                req_query_params,
                                req_body,
                            )
                            str_api_methods_by_tag += api_method_definition_string
                            # break

        return str_api_methods_by_tag

    def generate_api_file(self, root_path, tag_name):
        # 获取指定API的tag信息
        if not tag_name:
            for tag in self.swagger_tags:
                api_tag = tag["name"]
                api_class_name = tag["description"].replace(
                    " ", "_"
                )  # Swagger-UI 将tag中的空格用"_"代替，为后续用作文件名做准备
                # 获取Tag名下所有的API接口信息并转换成Python 文档
                strAPIs = self.__extract_swagger_api_paths(api_tag)
                strClass = FILE_TEMPLATE.format(api_class_name, strAPIs)
                # print(strClass)
                # 保存到指定目录下
                target_file = os.path.join(root_path, api_class_name) + ".py"
                with open(target_file, "w+", encoding="utf-8") as f:
                    f.writelines(strClass)
        else:
            for tag in self.swagger_tags:
                api_tag = tag["name"]
                if api_tag == tag_name:
                    api_class_name = tag["description"].replace(
                        " ", "_"
                    )  # Swagger-UI 将tag中的空格用"_"代替，为后续用作文件名做准备
                    # 获取Tag名下所有的API接口信息并转换成Python 文档
                    strAPIs = self.__extract_swagger_api_paths(api_tag)
                    strClass = FILE_TEMPLATE.format(api_class_name, strAPIs)
                    # print(strClass)
                    # 保存到指定目录下
                    target_file = os.path.join(root_path, api_class_name) + ".py"
                    with open(target_file, "w+", encoding="utf-8") as f:
                        f.writelines(strClass)

    def extract_api_records(self):
        api_list_by_swagger = []
        # 获取指定API的tag信息
        for tag in self.swagger_tags:
            api_tag = tag["name"]
            # print(api_tag)
            api_class_name = tag["description"].replace(
                " ", "_"
            )  # Swagger-UI 将tag中的空格用"_"代替，为后续用作文件名做准备
            # 获取Tag名下所有的API接口信息并转换成Python 文档
            for req_url, api_method_info in self.swagger_paths.items():
                # req_url: 请求的方法
                # api_method_info: API请求内容，包含parameters，tags, consumes
                if req_url:
                    req_url_flag = "/v1" + req_url.split("/v1")[-1]
                    for k, v in api_method_info.items():
                        api_method = k  # 默认api_method = api_info.keys()[0]
                        api_method_tag = v["tags"][0]
                        api_method_name = v["summary"]
                        if api_method_tag == api_tag:
                            api_list_by_swagger.append(
                                [
                                    api_tag,
                                    api_method_name,
                                    api_method,
                                    req_url,
                                    req_url_flag,
                                ]
                            )
                            # print(f'{req_url} >> {api_method} >> {api_method_name}')

        return api_list_by_swagger


def save_api_2_excel(swagger_urls, target_file):
    # 读取Swagger API的所有记录，并将其写入Excel中。
    total_api_records = []
    for swagger_url in swagger_urls:
        demo = AutoGenTestScripts(swagger_url)
        api_list = demo.extract_api_records()
        for api in api_list:
            api.insert(0, swagger_url)
            # print(api)
            total_api_records.append(api)

    # 列表数据转为数据框并生成Excel文件
    df = pd.DataFrame(
        total_api_records,
        columns=[
            "Swagger_UI",
            "API_Tag",
            "API_Summary",
            "API_Method",
            "API_Path",
            "API_Flag",
        ],
    )
    df.to_excel(target_file, sheet_name="Swagger_API_List", index=False)


def convert_api_2_python(swagger_urls, root_path, tag_name=None):
    for swagger_url in swagger_urls:
        domain = swagger_url.split("//")[1].split("/")[0]
        sub_folder = domain.split(".")[0].replace("-", "_")
        swagger_path = os.path.join(root_path, sub_folder)
        print(swagger_path)
        if not os.path.exists(swagger_path):
            os.mkdir(swagger_path)
        demo = AutoGenTestScripts(swagger_url)
        demo.generate_api_file(swagger_path, tag_name)


if __name__ == "__main__":
    bill_engine_swagger_urls = [
        "http://bill-data-fat.phoenix-t.xforceplus.com/v2/api-docs",
        "http://bill-engine-fat.phoenix-t.xforceplus.com/v2/api-docs",
    ]
    # bill_engine_swagger_urls = [
    #     'http://bill-account-fat.phoenix-t.xforceplus.com/v2/api-docs'
    # ]
    bill_swagger_urls = ["http://bill-test.phoenix-t.xforceplus.com/v2/api-docs"]
    pms_swagger_url = ["http://pms.xforceplus.com/pmsdev/v2/api-docs"]
    root_path = "D:/MyProjects/Billings/BillCenter_TestData/modules/"
    # bill_swagger_file = 'D:/MyProjects/Billings/BillCenter_TestData/bill_swagger_apis.xlsx'

    # # Swagger API 转 Python API
    # tag_name = '手工补偿接口'
    # tag_name = None
    # convert_api_2_python(bill_engine_swagger_urls, root_path, tag_name)

    # tag_name = None
    # convert_api_2_python(pms_swagger_url, root_path, tag_name)

    timestamp = time.strftime("%Y%m%d", time.localtime())
    # # 将计费引擎功能相关 Swagger API 转换成Excel文件
    bill_engine_swagger_file = (
        f"D:/MyProjects/Billings/BillCenter_TestData/{timestamp}_bill_engine_apis.xlsx"
    )
    save_api_2_excel(bill_engine_swagger_urls, bill_engine_swagger_file)

    # # 将小B计费功能相关 Swagger API 转换成Excel 文件
    bill_swagger_file = (
        f"D:/MyProjects/Billings/BillCenter_TestData/{timestamp}_bill_apis.xlsx"
    )
    save_api_2_excel(bill_swagger_urls, bill_swagger_file)
